package com.genexususa.eo.google.connection;

import com.genexususa.eo.bing.CampaignManagementServiceClasses.*;
import com.genexususa.eo.bing.CampaignManagementServiceClasses.AdGroup;
import com.genexususa.eo.google.data.*;
import com.google.api.ads.adwords.axis.v201409.ch.*;
import com.google.api.ads.adwords.axis.v201409.cm.*;
import com.google.api.ads.adwords.axis.utils.v201409.SelectorBuilder;
import com.google.api.ads.adwords.axis.v201409.cm.Campaign;
import com.google.api.ads.adwords.axis.v201409.cm.CampaignPage;
import com.google.api.ads.adwords.axis.v201409.cm.CampaignServiceInterface;
import com.google.api.ads.adwords.axis.v201409.cm.DateTimeRange;
import com.google.api.ads.adwords.axis.v201409.cm.Predicate;
import com.google.api.ads.adwords.axis.v201409.cm.PredicateOperator;
import com.google.api.ads.adwords.axis.v201409.cm.Selector;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.ws.Service;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

public class CustomerSyncManager {

    private final String CHANGED = "CHANGED";
    private final String REMOVED = "REMOVED";
    private final String NEW = "NEW";

    private final static Logger log = Logger.getLogger(CustomerSyncManager.class);

    private String _clientId;

    private ArrayList<GA_CampaignStats> accountCampaignsStats;
    private ArrayList<AdGroupReport> accountAdGroupReports;

    private ArrayList<PlatformReport> platforms;
    private ArrayList<LanguageReport> languages;
    private ArrayList<ProximityReport> proximities;
    private ArrayList<LocationReport> locations;

    private ArrayList<TextAdReport> textAds;
    private ArrayList<ImageAdReport> imageAds;
    private ArrayList<MobileAdReport> mobileAds;

    private ArrayList<KeywordReport> campaignKeywords;

    private ArrayList<AdGroupKeywordReport> adGroupKeywords;

    private ArrayList<AdGroupPlacementReport> adGroupPlacementReports;
    private ArrayList<AdGroupTopicReport> adGroupTopicReports;
    private ArrayList<AdGroupInterestReport> adGroupInterestReports;
    private ArrayList<AdGroupGenderReport> adGroupGenderReports;
    private ArrayList<AdGroupAgeReport> adGroupAgeReports;

    private ArrayList<AdExtensionLocationReport> extensionLocations;

    private ArrayList<GA_SitelinksFeedItem> sitelinksFeedItems;
    private ArrayList<GA_LocationExtensionsFeedItem> locationExtensionsFeedItems;
    private ArrayList<GA_CallsFeedItem> callsFeedItems;
    private ArrayList<LocationExtensionReport> locationExtensions;
    private ArrayList<CallsAdExtensionReport> calls;

    private ArrayList<FeedReport> feeds;

    private ArrayList<SitelinksReport> sitelinks;

    private ArrayList<Long> removedCampaigns;

    public void SetClientId(String clientId) {
        this._clientId = clientId;
    }

    public String GetClientId() {
        return _clientId;
    }

    public void Finalize() {

        SessionController sc = SessionController.getInstance();
        sc.RemoveSession(_clientId);
    }


    private static final int PAGE_SIZE = 5000;

    public void GetCustomersChangedData(String clientsData, String filePath, Long timeBetweenRequests, int retries){
        String[] clientsDataArray = clientsData.split(";");

        ArrayList<Thread> threads = new ArrayList<Thread>();

        for(String clientData : clientsDataArray){
            // clientData format: ClientId, StartDate, EndDate [, CampaignId]*
            String[] clientDataArray = clientData.split(",");
            if (clientDataArray.length >= 3) {
                String clientId = clientDataArray[0];
                String startDate = clientDataArray[1];
                String endDate = clientDataArray[2];
                ArrayList<String> campaignsToFilterOut = new ArrayList<String>();
                for (int i=3; i<clientDataArray.length; i++) {
                    campaignsToFilterOut.add(clientDataArray[i]);
                }
                GetChanges changes = new GetChanges(clientId, filePath, retries, startDate, endDate, campaignsToFilterOut);
                changes.start();
                //System.out.println(changes.getName() + " started!");
                threads.add(changes);
                try {
                    Thread.sleep(timeBetweenRequests);
                } catch (InterruptedException e) {
                    e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                    changes = new GetChanges(clientId, filePath, retries, startDate, endDate, campaignsToFilterOut);
                    changes.start();
                }
            }
        }


        for (Thread thread : threads){
            try{
                thread.join();
                System.out.println(thread.getName() + " ended!");
            }catch (InterruptedException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }
        }
    }

    public void GetCustomerChangedDataAllCampaigns(String accountId, String startDate, String endDate, String locationFile) {
        GetCustomerChangedData(accountId, startDate, endDate, new ArrayList<String>(), locationFile);
    }

    public void GetCustomerChangedData(String accountId, String startDate, String endDate, ArrayList<String> campaignsToFilterOut, String locationFile){
        GA_Report report = null;
        try {
            ServiceFactory sf = ServiceFactory.getInstance();

            this._clientId = accountId;

            CampaignServiceInterface campaignService = sf.GetCampaignService(accountId);
            CustomerSyncServiceInterface customerService = sf.GetCustomerSyncServiceInterface(accountId);


            ArrayList<Long> campaignIds = new ArrayList<Long>();
            //Predicate predicate = new Predicate("Status", PredicateOperator.NOT_EQUALS, new String[]{"REMOVED"});
            Selector selector = new SelectorBuilder()
                    .fields("Id")
                    .build();
           // selector.setPredicates(new Predicate[] {predicate});
            // Create date time range for the past 24 hours.
            DateTimeRange dateTimeRange = new DateTimeRange();
            dateTimeRange.setMin(new SimpleDateFormat("yyyyMMdd HHmmss").format(new SimpleDateFormat("yyyyMMdd HHmmss").parse(startDate)));
            dateTimeRange.setMax(new SimpleDateFormat("yyyyMMdd HHmmss").format(new SimpleDateFormat("yyyyMMdd HHmmss").parse(endDate)));

            CampaignPage campaigns = campaignService.get(selector);
            if (campaigns.getEntries() != null) {
                for (Campaign campaign : campaigns.getEntries()) {
                    campaignIds.add(campaign.getId());
                   // System.out.println(campaign.getId());
                }
            }

            removedCampaigns = new ArrayList<Long>();


            Predicate predicateRemoved = new Predicate("Status", PredicateOperator.EQUALS, new String[]{"REMOVED"});
            Selector selectorRemoved = new SelectorBuilder()
                    .fields("Id")
                    .build();
            selector.setPredicates(new Predicate[] {predicateRemoved});

            CampaignPage removedCampaignsPage = campaignService.get(selectorRemoved);
            if (removedCampaignsPage.getEntries() != null) {
                for (Campaign campaign : removedCampaignsPage.getEntries()) {
                    removedCampaigns.add(campaign.getId());
                    // System.out.println(campaign.getId());
                }
            }



            // Create selector.
            CustomerSyncSelector customerSyncSelector = new CustomerSyncSelector();
            customerSyncSelector.setDateTimeRange(dateTimeRange);

            customerSyncSelector
                    .setCampaignIds(ArrayUtils.toPrimitive(campaignIds.toArray(new Long[]{})));

            // Get all account changes for campaign.
            CustomerChangeData accountChanges = customerService.get(customerSyncSelector);

            boolean accountChanged = false;

            //<editor-fold desc="Account Changed">
            if (accountChanges != null && accountChanges.getChangedCampaigns() != null) {

                CampaignChangeData[] changedCampaigns = accountChanges.getChangedCampaigns();

                for (CampaignChangeData changedCampaign : changedCampaigns){

                    if (changedCampaign.getCampaignChangeStatus() == ChangeStatus.FIELDS_CHANGED ||
                            changedCampaign.getCampaignChangeStatus() == ChangeStatus.NEW){
                        accountChanged = true;
                        break;
                    }else{

                        if (changedCampaign.getChangedAdGroups() != null){
                            AdGroupChangeData[] changedAdGroups = changedCampaign.getChangedAdGroups();

                            for (AdGroupChangeData changedAdGroup : changedAdGroups){
                                if (changedAdGroup.getAdGroupChangeStatus() == ChangeStatus.FIELDS_CHANGED ||
                                        changedAdGroup.getAdGroupChangeStatus() == ChangeStatus.NEW){
                                    accountChanged = true;
                                    break;
                                }else{
                                    if (changedAdGroup.getChangedAds() != null) {
                                        if (changedAdGroup.getChangedAds().length > 0) {
                                            accountChanged = true;
                                            break;
                                        }
                                    }

                                    if (changedAdGroup.getChangedFeeds() != null){
                                        if (changedAdGroup.getChangedFeeds().length > 0) {
                                            accountChanged = true;
                                            break;
                                        }
                                    }

                                    if (changedAdGroup.getChangedCriteria() != null){
                                        if (changedAdGroup.getChangedCriteria().length > 0) {
                                            accountChanged = true;
                                            break;
                                        }
                                    }


                                    if (changedAdGroup.getChangedAdGroupBidModifierCriteria() != null){
                                        if (changedAdGroup.getChangedAdGroupBidModifierCriteria().length > 0) {
                                            accountChanged = true;
                                            break;
                                        }
                                    }

                                    if (changedAdGroup.getRemovedAdGroupBidModifierCriteria() != null){
                                        if (changedAdGroup.getRemovedAdGroupBidModifierCriteria().length > 0){
                                            accountChanged = true;
                                            break;
                                        }
                                    }

                                    if (changedAdGroup.getRemovedCriteria() != null){
                                        if (changedAdGroup.getRemovedCriteria().length > 0){
                                            accountChanged = true;
                                            break;
                                        }
                                    }

                                    if (changedAdGroup.getRemovedFeeds() != null){
                                        if (changedAdGroup.getRemovedFeeds().length > 0){
                                            accountChanged = true;
                                            break;
                                        }
                                    }
                                }
                            }
                        }

                        if (changedCampaign.getChangedFeeds() != null) {
                            if (changedCampaign.getChangedFeeds().length > 0) {
                                accountChanged = true;
                                break;
                            }
                        }

                        if (changedCampaign.getAddedCampaignCriteria() != null){
                            if (changedCampaign.getAddedCampaignCriteria().length > 0){
                                accountChanged = true;
                                break;
                            }
                        }

                        if (changedCampaign.getRemovedCampaignCriteria() != null){
                            if (changedCampaign.getRemovedCampaignCriteria().length > 0){
                                accountChanged = true;
                                break;
                            }
                        }

                        if (changedCampaign.getAddedAdExtensions() != null){
                            if (changedCampaign.getAddedAdExtensions().length > 0){
                                accountChanged = true;
                                break;
                            }
                        }

                        if (changedCampaign.getRemovedAdExtensions() != null){
                            if (changedCampaign.getRemovedAdExtensions().length > 0){
                                accountChanged = true;
                                break;
                            }
                        }

                        if (changedCampaign.getRemovedFeeds() != null){
                            if (changedCampaign.getRemovedFeeds().length > 0){
                                accountChanged = true;
                                break;
                            }

                        }


                    }

                    if (accountChanged){
                        break;
                    }
                }

            }
            //</editor-fold>
            if (accountChanged) {
                report = new GA_Report();
                if (accountChanges != null && accountChanges.getChangedCampaigns() != null) {

                    ArrayList<CampaignReport> changedCampaigns = new ArrayList<CampaignReport>();

                    ArrayList<Long> changedCampaignIds = new ArrayList<Long>();

                    for (CampaignChangeData campaignChanges : accountChanges.getChangedCampaigns()) {
                        changedCampaignIds.add(campaignChanges.getCampaignId());
                    }

                    //<editor-fold desc="Get All Data">
                    CampaignManager cm = new CampaignManager();
                    cm.SetClientId(this._clientId);
                    accountCampaignsStats = cm.GetCampaignStatsWithRemoved(campaignsToFilterOut);
                    report.Budgets = cm.GetBudgetStats();

                    cm.Finalize();

                    AccountManager am = new AccountManager();

                    report.Account = am.GetAccountReport(accountId);

                    AdGroupManager adm = new AdGroupManager();
                    accountAdGroupReports = adm.GetAdGroupStatsWithRemoved(accountId, campaignsToFilterOut);

                    CampaignTargetingManager ctm = new CampaignTargetingManager();
                    platforms = ctm.GetCampaignDevices(accountId);
                    languages = ctm.GetCampaignLanguages(accountId);

                    CampaignCriterionManager ccm = new CampaignCriterionManager();
                    campaignKeywords = ccm.GetKeywords(accountId, campaignsToFilterOut);

                    AdsManager adsManager = new AdsManager();

                    textAds = adsManager.GetTextAds(accountId);
                    imageAds = adsManager.GetImageAds(accountId);
                    mobileAds = adsManager.GetMobileAds(accountId);

                    AdGroupCriterionManager acm = new AdGroupCriterionManager();
                    adGroupKeywords = acm.GetAdGroupKeywordsWithRemoved(accountId);

                    adGroupPlacementReports = acm.GetAdGroupPlacements(accountId);
                    adGroupTopicReports = acm.GetAdGroupTopics(accountId);
                    adGroupInterestReports = acm.GetAdGroupInterests(accountId);
                    adGroupGenderReports = acm.GetAdGroupGenders(accountId);
                    adGroupAgeReports = acm.GetAdGroupAges(accountId);

                    proximities = ccm.GetProximities(accountId);
                    locations = ccm.GetLocations(accountId);
                    LocationCriterionManager lcm = new LocationCriterionManager();
                    lcm.SetClientId(accountId);
                    lcm.getLocationsExtraData(locations);

                    FeedManager fm = new FeedManager();

                    feeds = fm.GetAllFeedsReport(accountId);
                    sitelinksFeedItems = fm.GetSitelinksFeedItemReport(accountId);
                    //report.SitelinksFeedItems = sitelinksFeedItems;

                    locationExtensionsFeedItems = fm.GetLocationExtensionsFeedItemReport(accountId);
                    //report.LocationExtensionsFeedItems = locationExtensionsFeedItems;

                    callsFeedItems = fm.GetCallsFeedItemReport(accountId);
                    //report.CallsFeedItems = callsFeedItems;

                    AdExtensionManager adExtManager = new AdExtensionManager();
                    extensionLocations = adExtManager.GetAdExtensionLocationReport(accountId);

                    sitelinks = adExtManager.GetFeedItemsSitelinksReport(accountId);
                    report.Sitelinks = sitelinks;

                    locationExtensions = adExtManager.GetFeedItemsLocationExtensionReport(accountId);
                    report.LocationExtensions = locationExtensions;


                    calls = adExtManager.GetFeedItemsAdExtensionsCallsReport(accountId);
                    report.Calls = calls;


                    //</editor-fold>

                    for (CampaignChangeData campaignChanges : accountChanges.getChangedCampaigns()) {
                        CampaignReport changedCampaign = new CampaignReport();
                        if (campaignChanges.getCampaignChangeStatus() == ChangeStatus.FIELDS_CHANGED ||
                                campaignChanges.getCampaignChangeStatus() == ChangeStatus.FIELDS_UNCHANGED) {

                            // If the fields or the campaign has changed
                            changedCampaign = getChangedCampaign(campaignChanges);

                        } else if (campaignChanges.getCampaignChangeStatus() == ChangeStatus.NEW) {
                            // If the campaign is new we bring all the data, all the ads, all the keywords, etc
                            changedCampaign = getNewCampaign(campaignChanges);

                        }

                        if (changedCampaign != null) {

                            long[] changedFeedIds = campaignChanges.getChangedFeeds();

                            if (campaignChanges.getChangedFeeds() != null) {

                                for (long changedFeedId : changedFeedIds) {

                                    if (getCampaignFeedReport(Long.valueOf(changedFeedId)) != null) {
                                        report.Feeds.add(getCampaignFeedReport(Long.valueOf(changedFeedId)));
                                    }

                                    if (getCampaignSitelinksFeedItem(Long.valueOf(changedFeedId)) != null) {
                                        report.SitelinksFeedItems.add(getCampaignSitelinksFeedItem(Long.valueOf(changedFeedId)));
                                    }

                                    if (getCampaignLocationExtensionFeedItems(Long.valueOf(changedFeedId)) != null) {
                                        report.LocationExtensionsFeedItems.add(getCampaignLocationExtensionFeedItems(Long.valueOf(changedFeedId)));
                                    }

                                    if (getCampaignCallFeedItems(Long.valueOf(changedFeedId)) != null) {
                                        report.CallsFeedItems.add(getCampaignCallFeedItems(Long.valueOf(changedFeedId)));
                                    }
                                }


                            }
                            report.Campaigns.add(changedCampaign);
                        }
                    }

                    report.Calls = calls;
                    report.Sitelinks = sitelinks;

                    if (accountChanges.getChangedFeeds() != null) {

                        for (FeedChangeData feedChangeData : accountChanges.getChangedFeeds()) {

                            FeedReport changedFeed = null;

                            if (feedChangeData.getFeedChangeStatus() == ChangeStatus.FIELDS_CHANGED ||
                                    feedChangeData.getFeedChangeStatus() == ChangeStatus.FIELDS_UNCHANGED) {

                                changedFeed = getChangedFeed(feedChangeData);

                                if (changedFeed != null) {
                                    report.Feeds.add(changedFeed);
                                }

                            } else {
                                report.Feeds = feeds;

                            }

                        }
                    }
                    System.out.println("Account " + accountId + " has changes!");
                    log.info("Account " + accountId + " has changes in the date range: \n\tStart Date: " + startDate + "\n\tEnd Date: " + endDate);
                }
            }else{

                System.out.println("Account " + accountId + " has no changes!");
                log.info("Account " + accountId + " has no changes in the date range: \n\tStart Date: " + startDate + "\n\tEnd Date: " + endDate);

            }
        } catch (Exception exc) {
            report = new GA_Report();
            report.HasError = true;
            report.Errors = new ErrorsStruct();
            report.Errors.Message = exc.getMessage();
            report.Errors.Errors = new ArrayList<com.genexususa.eo.google.data.Error>();
            com.genexususa.eo.google.data.Error err = new com.genexususa.eo.google.data.Error();
            StringWriter st = new StringWriter();
            exc.printStackTrace(new PrintWriter(st));
            err.UnknownError = st.toString();
            report.Errors.Errors.add(err);
        }

        if (report != null) {
            try {
                String result = "";
                JAXBContext contextObj = JAXBContext.newInstance(GA_Report.class);
                Marshaller marshallerObj = contextObj.createMarshaller();
                marshallerObj.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
                StringWriter sw = new StringWriter();
                marshallerObj.marshal(report, sw);
                result = sw.getBuffer().toString();
                //System.out.println(result);
                FileWriter fw = new FileWriter(locationFile + File.separator + accountId + ".xml");
                BufferedWriter bw = new BufferedWriter(fw);
                bw.write(result);
                bw.flush();
                bw.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private GA_CallsFeedItem getCampaignCallFeedItems(Long feedId) {
        for(GA_CallsFeedItem callsFeedItem : callsFeedItems){
            if (callsFeedItem.FeedId.equals(feedId)){
                return callsFeedItem;
            }
        }
        return null;
    }

    private GA_LocationExtensionsFeedItem getCampaignLocationExtensionFeedItems(Long feedId) {
        for (GA_LocationExtensionsFeedItem locationExtensionReport : locationExtensionsFeedItems){
            if (locationExtensionReport.FeedId.equals(feedId)){
                return locationExtensionReport;
            }
        }
        return null;
    }

    private GA_SitelinksFeedItem getCampaignSitelinksFeedItem(Long feedId) {
        for (GA_SitelinksFeedItem sitelinksFeedItem : sitelinksFeedItems){
            if (sitelinksFeedItem.FeedId.equals(feedId)){
                return sitelinksFeedItem;
            }
        }

        return null;
    }

    private FeedReport getChangedFeed(FeedChangeData feedChangeData) {
        for (FeedReport feed : feeds){
            if (feed.FeedId.equals(feedChangeData.getFeedId())){
                return feed;
            }
        }

        return null;
    }

    private CampaignReport getNewCampaign(CampaignChangeData campaignChanges) {

        CampaignReport campaignReport = new CampaignReport();

        GA_CampaignStats campaignStats = getCampaignStat(campaignChanges.getCampaignId());

        //<editor-fold desc="Get Campaign Stats">
        campaignReport.AdServingOptimizationStatus = campaignStats.AdServingOptimizationStatus;
        campaignReport.BidCeiling = campaignStats.BidCeiling;
        campaignReport.BiddingStrategyType = campaignStats.BiddingStrategyType;
        campaignReport.BidType = campaignStats.BidType;
        campaignReport.BudgetId = campaignStats.BudgetId;
        campaignReport.EndDate = campaignStats.EndDate;
        campaignReport.EnhancedCpcEnabled = campaignStats.EnhancedCpcEnabled;
        campaignReport.FrequencyCapMaxImpressions = campaignStats.FrequencyCapMaxImpressions;
        campaignReport.Id = campaignStats.Id;
        campaignReport.Level = campaignStats.Level;
        campaignReport.Name = campaignStats.Name;
        campaignReport.PricingMode = campaignStats.PricingMode;
        campaignReport.StartDate = campaignStats.StartDate;
        campaignReport.Status = campaignStats.Status;
        /*if (campaignReport.Status.equalsIgnoreCase("D")){
            campaignReport.SyncStatus = REMOVED;
        }else{
            campaignReport.SyncStatus = CHANGED;
        }*/
        campaignReport.TargetContentNetwork = campaignStats.TargetContentNetwork;
        campaignReport.TargetGoogleSearch = campaignStats.TargetGoogleSearch;
        campaignReport.TargetPartnerSearchNetwork = campaignStats.TargetPartnerSearchNetwork;
        campaignReport.TargetSearchNetwork = campaignStats.TargetSearchNetwork;
        campaignReport.TimeUnit = campaignStats.TimeUnit;
        campaignReport.GeoTargetNegativeType = campaignStats.GeoTargetNegativeType;
        campaignReport.GeoTargetPositiveType = campaignStats.GeoTargetPositiveType;
        campaignReport.KeywordMatch = campaignStats.KeywordMatch;
        campaignReport.RealTimeBidding = campaignStats.RealTimeBidding;
        campaignReport.AdvertisingChannelType = campaignStats.AdvertisingChannelType;
        campaignReport.BiddingStrategyId = campaignStats.BiddingStrategyId;
        campaignReport.BiddingStrategyName = campaignStats.BiddingStrategyName;
        //</editor-fold>

        //<editor-fold desc="Ad Groups">
        for (AdGroupReport adGroupReport : accountAdGroupReports){
            if (adGroupReport.CampaignId.equals(campaignChanges.getCampaignId())){

                // AdGroupKeywords
                for(AdGroupKeywordReport adGroupKeywordReport :  adGroupKeywords){
                    if(adGroupKeywordReport.AdGroupId.equals(adGroupReport.Id)){
                        adGroupReport.AdGroupKeywords.add(adGroupKeywordReport);
                    }
                }

                // TextAds
                for(TextAdReport textAdReport : textAds){
                    if(textAdReport.AdGroupId.equals(adGroupReport.Id)){
                        adGroupReport.TextAds.add(textAdReport);
                    }
                }

                // ImageAds
                for(ImageAdReport imageAdReport : imageAds){
                    if(imageAdReport.AdGroupId.equals(adGroupReport.Id)){
                        adGroupReport.ImageAds.add(imageAdReport);
                    }
                }

                // MobileAds
                for(MobileAdReport mobileAdReport : mobileAds){
                    if(mobileAdReport.AdGroupId.equals(adGroupReport.Id)){
                        adGroupReport.MobileAds.add(mobileAdReport);
                    }
                }

                for(AdGroupPlacementReport placementReport : adGroupPlacementReports){
                    if(placementReport.AdGroupId.equals(adGroupReport.Id)){
                        adGroupReport.AdGroupPlacements.add(placementReport);
                    }
                }

                for(AdGroupTopicReport adGroupTopicReport : adGroupTopicReports){
                    if(adGroupTopicReport.AdGroupId.equals(adGroupReport.Id)){
                        adGroupReport.AdGroupTopics.add(adGroupTopicReport);
                    }
                }

                for(AdGroupInterestReport adGroupInterestReport : adGroupInterestReports){
                    if(adGroupInterestReport.AdGroupId.equals(adGroupReport.Id)){
                        adGroupReport.AdGroupInterests.add(adGroupInterestReport);
                    }
                }

                for(AdGroupGenderReport adGroupGenderReport : adGroupGenderReports){
                    if(adGroupGenderReport.AdGroupId.equals(adGroupReport.Id)){
                        adGroupReport.AdGroupGenders.add(adGroupGenderReport);
                    }
                }

                for(AdGroupAgeReport adGroupAgeReport : adGroupAgeReports){
                    if(adGroupAgeReport.AdGroupId.equals(adGroupReport.Id)){
                        adGroupReport.AdGroupAges.add(adGroupAgeReport);
                    }
                }

                campaignReport.AdGroups.add(adGroupReport);

            }
        }
        //</editor-fold>

        //<editor-fold desc="Extension Locations">
        // ExtensionLocations
        for(AdExtensionLocationReport adExtensionLocationReport : extensionLocations){
            if(adExtensionLocationReport.CampaignId.equals(campaignChanges.getCampaignId())){
                campaignReport.ExtensionLocations.add(adExtensionLocationReport);
            }
        }
        //</editor-fold>

        //<editor-fold desc="Languages">
        // Languages
        for(LanguageReport languageReport : languages){
            if(languageReport.CampaignId.equals(campaignChanges.getCampaignId())){
                campaignReport.Languages.add(languageReport);
            }
        }
        //</editor-fold>

        //<editor-fold desc="Platforms">
        // Platforms
        for(PlatformReport platformReport : platforms){
            if(platformReport.CampaignId.equals(campaignChanges.getCampaignId())){
                campaignReport.Platforms.add(platformReport);
            }
        }
        //</editor-fold>

        //<editor-fold desc="Keywords">
        // Keywords
        for(KeywordReport keywordReport : campaignKeywords){
            if(keywordReport.CampaignId.equals(campaignChanges.getCampaignId())){
                campaignReport.Keywords.add(keywordReport);
            }
        }
        //</editor-fold>

        //<editor-fold desc="Proximities">
        // Proximities
        for(ProximityReport proximityReport : proximities){
            if(proximityReport.CampaignId.equals(campaignChanges.getCampaignId())){
                campaignReport.Proximities.add(proximityReport);
            }
        }
        //</editor-fold>

        //<editor-fold desc="Locations">
        // Locations
        for(LocationReport locationReport : locations){
            if(locationReport.CampaignId.equals(campaignChanges.getCampaignId())){
                campaignReport.Locations.add(locationReport);
            }
        }
        //</editor-fold>


        if (campaignChanges.getChangedAdGroups() != null && campaignChanges.getChangedAdGroups().length > 0){

            /*for (AdGroupChangeData adGroupChangeData : campaignChanges.getChangedAdGroups()){

                AdGroupReport adGroupReport = getChangedAdGroup(adGroupChangeData);




            }*/





        }

        return campaignReport;
    }

    private CampaignReport getChangedCampaign(CampaignChangeData campaignChanges) {
        CampaignReport campaignReport = new CampaignReport();

        GA_CampaignStats campaignStats = getCampaignStat(campaignChanges.getCampaignId());

        if (campaignStats != null) {

            //<editor-fold desc="Campaign Stats">

                campaignReport.AdServingOptimizationStatus = campaignStats.AdServingOptimizationStatus;
                campaignReport.BidCeiling = campaignStats.BidCeiling;
                campaignReport.BiddingStrategyType = campaignStats.BiddingStrategyType;
                campaignReport.BidType = campaignStats.BidType;
                campaignReport.BudgetId = campaignStats.BudgetId;
                campaignReport.EndDate = campaignStats.EndDate;
                campaignReport.EnhancedCpcEnabled = campaignStats.EnhancedCpcEnabled;
                campaignReport.FrequencyCapMaxImpressions = campaignStats.FrequencyCapMaxImpressions;
                campaignReport.Id = campaignStats.Id;
                campaignReport.Level = campaignStats.Level;
                campaignReport.Name = campaignStats.Name;
                campaignReport.PricingMode = campaignStats.PricingMode;
                campaignReport.StartDate = campaignStats.StartDate;
                campaignReport.Status = campaignStats.Status;
                /*if (campaignReport.Status.equalsIgnoreCase("D")) {
                    campaignReport.SyncStatus = REMOVED;
                } else {
                    campaignReport.SyncStatus = CHANGED;
                }*/
                campaignReport.TargetContentNetwork = campaignStats.TargetContentNetwork;
                campaignReport.TargetGoogleSearch = campaignStats.TargetGoogleSearch;
                campaignReport.TargetPartnerSearchNetwork = campaignStats.TargetPartnerSearchNetwork;
                campaignReport.TargetSearchNetwork = campaignStats.TargetSearchNetwork;
                campaignReport.TimeUnit = campaignStats.TimeUnit;
                campaignReport.GeoTargetNegativeType = campaignStats.GeoTargetNegativeType;
                campaignReport.GeoTargetPositiveType = campaignStats.GeoTargetPositiveType;
                campaignReport.KeywordMatch = campaignStats.KeywordMatch;
                campaignReport.RealTimeBidding = campaignStats.RealTimeBidding;
                campaignReport.AdvertisingChannelType = campaignStats.AdvertisingChannelType;
                campaignReport.BiddingStrategyId = campaignStats.BiddingStrategyId;
                campaignReport.BiddingStrategyName = campaignStats.BiddingStrategyName;

            //</editor-fold>

            if (campaignChanges.getChangedAdGroups() != null) {

                for (AdGroupChangeData adGroupChangeData : campaignChanges.getChangedAdGroups()) {
                    AdGroupReport adGroupReport = new AdGroupReport();
                    if (adGroupChangeData.getAdGroupChangeStatus() == ChangeStatus.FIELDS_CHANGED ||
                            adGroupChangeData.getAdGroupChangeStatus() == ChangeStatus.FIELDS_UNCHANGED) {

                        adGroupReport = getChangedAdGroup(adGroupChangeData);
                    } else if (adGroupChangeData.getAdGroupChangeStatus() == ChangeStatus.NEW) {
                        adGroupReport = getNewAdGroup(adGroupChangeData);
                    }

                    campaignReport.AdGroups.add(adGroupReport);

                }
            }


            //<editor-fold desc="Campaign Criteria">


            if (campaignChanges.getAddedCampaignCriteria() != null) {
                long[] criteriaIds = campaignChanges.getAddedCampaignCriteria();

                for (long criterionId : criteriaIds) {

                    if (getCampaignKeywordReport(Long.valueOf(criterionId)) != null) {
                        KeywordReport keywordReport = getCampaignKeywordReport(Long.valueOf(criterionId));
                        //keywordReport.SyncStatus = CHANGED;
                        campaignReport.Keywords.add(keywordReport);
                    }

                    if (getPlatformReport(Long.valueOf(criterionId)) != null) {
                        PlatformReport platformReport = getPlatformReport(Long.valueOf(criterionId));
                       // platformReport.SyncStatus = CHANGED;
                        campaignReport.Platforms.add(platformReport);
                    }

                    if (getLanguageReport(Long.valueOf(criterionId)) != null) {
                        LanguageReport languageReport = getLanguageReport(Long.valueOf(criterionId));
                        //languageReport.SyncStatus = CHANGED;
                        campaignReport.Languages.add(languageReport);
                    }

                    if (getLocationReport(Long.valueOf(criterionId)) != null) {
                        LocationReport locationReport = getLocationReport(Long.valueOf(criterionId));
                        //locationReport.SyncStatus = CHANGED;
                        campaignReport.Locations.add(locationReport);
                    }

                    if (getProximityReport(Long.valueOf(criterionId)) != null) {
                        ProximityReport proximityReport = getProximityReport(Long.valueOf(criterionId));
                        //proximityReport.SyncStatus = CHANGED;
                        campaignReport.Proximities.add(proximityReport);
                    }

                }
            }

            if (campaignChanges.getRemovedCampaignCriteria() != null){

                long[] criteriaIds = campaignChanges.getRemovedCampaignCriteria();

                for (long criterionId : criteriaIds) {

                    if (getCampaignKeywordReport(Long.valueOf(criterionId)) != null) {
                        KeywordReport keywordReport = getCampaignKeywordReport(Long.valueOf(criterionId));
                        //keywordReport.SyncStatus = REMOVED;
                        campaignReport.Keywords.add(keywordReport);
                    }

                    if (getPlatformReport(Long.valueOf(criterionId)) != null) {
                        PlatformReport platformReport = getPlatformReport(Long.valueOf(criterionId));
                        //platformReport.SyncStatus = REMOVED;
                        campaignReport.Platforms.add(platformReport);
                    }

                    if (getLanguageReport(Long.valueOf(criterionId)) != null) {
                        LanguageReport languageReport = getLanguageReport(Long.valueOf(criterionId));
                        //languageReport.SyncStatus = REMOVED;
                        campaignReport.Languages.add(languageReport);
                    }

                    if (getLocationReport(Long.valueOf(criterionId)) != null) {
                        LocationReport locationReport = getLocationReport(Long.valueOf(criterionId));
                        //locationReport.SyncStatus = REMOVED;
                        campaignReport.Locations.add(locationReport);
                    }

                    if (getProximityReport(Long.valueOf(criterionId)) != null) {
                        ProximityReport proximityReport = getProximityReport(Long.valueOf(criterionId));
                        //proximityReport.SyncStatus = REMOVED;
                        campaignReport.Proximities.add(proximityReport);
                    }

                }

            }
            //</editor-fold>



        /*for (AdGroupReport adGroupReport : accountAdGroupReports) {
            if (adGroupReport.CampaignId.equals(campaignChanges.getCampaignId())) {

                // AdGroupKeywords
                for (AdGroupKeywordReport adGroupKeywordReport : adGroupKeywords) {
                    if (adGroupKeywordReport.AdGroupId.equals(adGroupReport.Id)) {
                        adGroupReport.AdGroupKeywords.add(adGroupKeywordReport);
                    }
                }
            }
        }*/
        }else return null;

        return campaignReport;
    }

    private boolean isRemovedCampaign(Long campaignId){
        for (Long id : removedCampaigns){
            if (id.equals(campaignId)){
                return true;
            }
        }
        return false;
    }

    private FeedReport getCampaignFeedReport(Long feedId){
        for (FeedReport feedReport : feeds){
            if (feedReport.FeedId.equals(feedId)){
                return feedReport;
            }
        }
        return null;
    }

    private AdGroupReport getChangedAdGroup(AdGroupChangeData adGroupChange) {

        AdGroupReport report = null;
        for (AdGroupReport adGroupReport : accountAdGroupReports){
            if (adGroupReport.Id.equals(adGroupChange.getAdGroupId()))
                report = adGroupReport;
        }


        if (report != null){

            long[] changedAds = adGroupChange.getChangedAds();

            //<editor-fold desc="Ads">
            if (adGroupChange.getChangedAds() != null) {

                for (TextAdReport textAdReport : textAds) {

                    if (containsId(changedAds, textAdReport.Id.longValue())) {
                        if (textAdReport.AdGroupId.equals(report.Id)) {
                            report.TextAds.add(textAdReport);
                        }
                    }
                }

                // ImageAds
                for (ImageAdReport imageAdReport : imageAds) {

                    if (containsId(changedAds, imageAdReport.Id.longValue())) {

                        if (imageAdReport.AdGroupId.equals(report.Id)) {
                            report.ImageAds.add(imageAdReport);
                        }
                    }
                }

                // MobileAds
                for (MobileAdReport mobileAdReport : mobileAds) {

                    if (containsId(changedAds, mobileAdReport.Id.longValue())) {

                        if (mobileAdReport.AdGroupId.equals(report.Id)) {
                            report.MobileAds.add(mobileAdReport);
                        }
                    }
                }
            }
            //</editor-fold>

            //<editor-fold desc="AdGroups Criteria">
            if (adGroupChange.getChangedCriteria() != null){

                long[] criteriaIds = adGroupChange.getChangedCriteria();

                for (long criterionId : criteriaIds){
                    if (getAdGroupKeywordReport(Long.valueOf(criterionId)) != null){
                        AdGroupKeywordReport adGroupKeywordReport = getAdGroupKeywordReport(Long.valueOf(criterionId));
                        //adGroupKeywordReport.SyncStatus = CHANGED;
                        report.AdGroupKeywords.add(adGroupKeywordReport);
                    }

                    if (getAdGroupAgeReport(Long.valueOf(criterionId)) != null){
                        AdGroupAgeReport adGroupAgeReport = getAdGroupAgeReport(Long.valueOf(criterionId));
                        //adGroupAgeReport.SyncStatus = CHANGED;
                        report.AdGroupAges.add(adGroupAgeReport);
                    }

                    if (getAdGroupGenderReport(Long.valueOf(criterionId)) != null){
                        AdGroupGenderReport adGroupGenderReport = getAdGroupGenderReport(Long.valueOf(criterionId));
                        //adGroupGenderReport.SyncStatus = CHANGED;
                        report.AdGroupGenders.add(adGroupGenderReport);
                    }

                    if (getAdGroupInterestReport(Long.valueOf(criterionId))!= null){
                        AdGroupInterestReport adGroupInterestReport = getAdGroupInterestReport(Long.valueOf(criterionId));
                        //adGroupInterestReport.SyncStatus = CHANGED;
                        report.AdGroupInterests.add(adGroupInterestReport);

                    }

                    if (getAdGroupPlacementReport(Long.valueOf(criterionId)) != null){
                        AdGroupPlacementReport adGroupPlacementReport = getAdGroupPlacementReport(Long.valueOf(criterionId));
                        //adGroupPlacementReport.SyncStatus = CHANGED;
                        report.AdGroupPlacements.add(adGroupPlacementReport);
                    }

                    if (getAdGroupTopicReport(Long.valueOf(criterionId)) != null){
                        AdGroupTopicReport adGroupTopicReport = getAdGroupTopicReport(Long.valueOf(criterionId));
                       // adGroupTopicReport.SyncStatus = CHANGED;
                        report.AdGroupTopics.add(adGroupTopicReport);
                    }
                }

            }

            if (adGroupChange.getRemovedCriteria() != null){

                long[] criteriaIds = adGroupChange.getRemovedCriteria();

                for (long criterionId : criteriaIds){
                    if (getAdGroupKeywordReport(Long.valueOf(criterionId)) != null){
                        AdGroupKeywordReport adGroupKeywordReport = getAdGroupKeywordReport(Long.valueOf(criterionId));
                        //adGroupKeywordReport.SyncStatus = REMOVED;
                        report.AdGroupKeywords.add(adGroupKeywordReport);
                    }

                    if (getAdGroupAgeReport(Long.valueOf(criterionId)) != null){
                        AdGroupAgeReport adGroupAgeReport = getAdGroupAgeReport(Long.valueOf(criterionId));
                        //adGroupAgeReport.SyncStatus = REMOVED;
                        report.AdGroupAges.add(adGroupAgeReport);
                    }

                    if (getAdGroupGenderReport(Long.valueOf(criterionId)) != null){
                        AdGroupGenderReport adGroupGenderReport = getAdGroupGenderReport(Long.valueOf(criterionId));
                        //adGroupGenderReport.SyncStatus = REMOVED;
                        report.AdGroupGenders.add(adGroupGenderReport);
                    }

                    if (getAdGroupInterestReport(Long.valueOf(criterionId))!= null){
                        AdGroupInterestReport adGroupInterestReport = getAdGroupInterestReport(Long.valueOf(criterionId));
                        //adGroupInterestReport.SyncStatus = REMOVED;
                        report.AdGroupInterests.add(adGroupInterestReport);

                    }

                    if (getAdGroupPlacementReport(Long.valueOf(criterionId)) != null){
                        AdGroupPlacementReport adGroupPlacementReport = getAdGroupPlacementReport(Long.valueOf(criterionId));
                        //adGroupPlacementReport.SyncStatus = REMOVED;
                        report.AdGroupPlacements.add(adGroupPlacementReport);
                    }

                    if (getAdGroupTopicReport(Long.valueOf(criterionId)) != null){
                        AdGroupTopicReport adGroupTopicReport = getAdGroupTopicReport(Long.valueOf(criterionId));
                        //adGroupTopicReport.SyncStatus = REMOVED;
                        report.AdGroupTopics.add(adGroupTopicReport);
                    }
                }

            }
            //</editor-fold>


        }

        return report;
    }

    private AdGroupReport getNewAdGroup(AdGroupChangeData adGroupChange) {

        AdGroupReport report = null;
        for (AdGroupReport adGroupReport : accountAdGroupReports){
            if (adGroupReport.Id.equals(adGroupChange.getAdGroupId()))
                report = adGroupReport;
        }


        if (report != null){


                // AdGroupKeywords
                for(AdGroupKeywordReport adGroupKeywordReport :  adGroupKeywords){
                    if(adGroupKeywordReport.AdGroupId.equals(report.Id)){
                        report.AdGroupKeywords.add(adGroupKeywordReport);
                    }
                }

                // TextAds
                for(TextAdReport textAdReport : textAds){
                    if(textAdReport.AdGroupId.equals(report.Id)){
                        report.TextAds.add(textAdReport);
                    }
                }

                // ImageAds
                for(ImageAdReport imageAdReport : imageAds){
                    if(imageAdReport.AdGroupId.equals(report.Id)){
                        report.ImageAds.add(imageAdReport);
                    }
                }

                // MobileAds
                for(MobileAdReport mobileAdReport : mobileAds){
                    if(mobileAdReport.AdGroupId.equals(report.Id)){
                        report.MobileAds.add(mobileAdReport);
                    }
                }

                for(AdGroupPlacementReport placementReport : adGroupPlacementReports){
                    if(placementReport.AdGroupId.equals(report.Id)){
                        report.AdGroupPlacements.add(placementReport);
                    }
                }

                for(AdGroupTopicReport adGroupTopicReport : adGroupTopicReports){
                    if(adGroupTopicReport.AdGroupId.equals(report.Id)){
                        report.AdGroupTopics.add(adGroupTopicReport);
                    }
                }

                for(AdGroupInterestReport adGroupInterestReport : adGroupInterestReports){
                    if(adGroupInterestReport.AdGroupId.equals(report.Id)){
                        report.AdGroupInterests.add(adGroupInterestReport);
                    }
                }

                for(AdGroupGenderReport adGroupGenderReport : adGroupGenderReports){
                    if(adGroupGenderReport.AdGroupId.equals(report.Id)){
                        report.AdGroupGenders.add(adGroupGenderReport);
                    }
                }

                for(AdGroupAgeReport adGroupAgeReport : adGroupAgeReports){
                    if(adGroupAgeReport.AdGroupId.equals(report.Id)){
                        report.AdGroupAges.add(adGroupAgeReport);
                    }
                }




        }

        return report;
    }

    private AdGroupKeywordReport getAdGroupKeywordReport(Long criterionId){

        for (AdGroupKeywordReport adGroupKeywordReport : adGroupKeywords){
            if (adGroupKeywordReport.Id.equals(criterionId)){
                return adGroupKeywordReport;
            }
        }

        return null;
    }

    private AdGroupPlacementReport getAdGroupPlacementReport(Long criterionId){

        for (AdGroupPlacementReport adGroupPlacementReport : adGroupPlacementReports){
            if (adGroupPlacementReport.Id.equals(criterionId))
                return adGroupPlacementReport;
        }

        return null;
    }

    private AdGroupTopicReport getAdGroupTopicReport(Long criterionId){
        for (AdGroupTopicReport adGroupTopicReport : adGroupTopicReports){
            if (adGroupTopicReport.Id.equals(criterionId))
                return adGroupTopicReport;
        }
        return null;
    }

    private AdGroupInterestReport getAdGroupInterestReport(Long criterionId){
        for (AdGroupInterestReport adGroupInterestReport : adGroupInterestReports){
            if (adGroupInterestReport.Id.equals(criterionId))
                return adGroupInterestReport;
        }
        return null;
    }

    private AdGroupGenderReport getAdGroupGenderReport(Long criterionId){
        for (AdGroupGenderReport adGroupGenderReport : adGroupGenderReports){
            if (adGroupGenderReport.Id.equals(criterionId))
                return adGroupGenderReport;
        }
        return null;
    }

    private AdGroupAgeReport getAdGroupAgeReport(Long criterionId){
        for (AdGroupAgeReport adGroupAgeReport : adGroupAgeReports){
            if (adGroupAgeReport.Id.equals(criterionId))
                return adGroupAgeReport;
        }
        return null;
    }

    private KeywordReport getCampaignKeywordReport(Long criterionId){
        for (KeywordReport keywordReport : campaignKeywords){
            if (keywordReport.Id.equals(criterionId))
                return keywordReport;
        }

        return null;
    }

    private LanguageReport getLanguageReport(Long criterionId){
        for (LanguageReport languageReport : languages){
            if (languageReport.Id.equals(criterionId))
                return languageReport;
        }
        return null;
    }

    private PlatformReport getPlatformReport(Long criterionId){
        for (PlatformReport platformReport : platforms){
            if (platformReport.Id.equals(criterionId))
                return platformReport;
        }
        return null;
    }

    private ProximityReport getProximityReport(Long criterionId){
        for (ProximityReport proximityReport : proximities){
            if (proximityReport.Id.equals(criterionId))
                return proximityReport;
        }
        return null;
    }

    private LocationReport getLocationReport(Long criterionId){
        for (LocationReport locationReport : locations){
            if (locationReport.Id.equals(criterionId)){
                return locationReport;
            }
        }
        return null;
    }

    private GA_CampaignStats getCampaignStat(Long campaignId){

        for (GA_CampaignStats campaignStats : accountCampaignsStats){
            if (campaignStats.Id.equals(campaignId))
                return campaignStats;
        }

        return null;
    }

    private static String getFormattedList(long[] idList) {
        if (idList == null) {
            idList = new long[]{};
        }
        return new StringBuilder().append("{")
                .append(StringUtils.join(ArrayUtils.toObject(idList), ','))
                .append("}").toString();
    }

    private boolean containsId(long[] ids, long id){

        boolean result = false;

        for (int i = 0; i < ids.length; i++){
            if (ids[i] == id){
                return true;
            }
        }

        return result;
    }
}

class GetChanges extends Thread{
    private String clientId;
    private String locationFile;
    private int retries = 5;
    private String startDate;
    private String endDate;
    private ArrayList<String> campaignsToFilterOut;

    GetChanges(String clientId, String locationFile, int retries, String startDate, String endDate, ArrayList<String> campaignsToFilterOut){
        this.clientId = clientId;
        this.locationFile = locationFile;
        this.retries = retries;
        this.startDate = startDate;
        this.endDate = endDate;
        this.campaignsToFilterOut = campaignsToFilterOut;
    }

    public void run(){
        CustomerSyncManager customerSyncManager = new CustomerSyncManager();

        int i = 0;


            customerSyncManager.GetCustomerChangedData(clientId, startDate, endDate, campaignsToFilterOut, locationFile);

    }
}
